//==============================================================================
//
//         DList - the double linked list class in the ofc-library
//
//               Copyright (C) 2003  Dick van Oudheusden
//  
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free
// Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//==============================================================================
// 
//  $Date: 2008-08-03 18:31:55 $ $Revision: 1.17 $
//
//==============================================================================

#include "ofc/DList.h"


#if _INTERFACE_

#include "ofc/config.h"

#include "ofc/DText.h"

#include "ofc/DStackable.h"
#include "ofc/DQueuable.h"


typedef struct _DListNode
{
  struct _DListNode  *_next;   // the next node (or NULL)
  struct _DListNode  *_prev;   // the previous node (or NULL)
  id                  _object; // the object in the node (or nil)
} DListNode;


//
// The DList class implements a number of methods for manipulating double linked
// lists. 
//
// @example
// #include <stdio.h>
// #include "ofc/DList.h"
// #include "ofc/DInt.h"
// #include "ofc/DText.h"
// 
// int main(int argc, char *argv[])
// {
//   DList         *list = [DList new];
//   DListIterator *iter;
//   DInt          *nr;
//   DText         *str;
//   DInt          *nr7;
//   id             obj;
//                                        // Add strings and numbers to the list
//   nr = [DInt alloc]; [nr init :4];
//   [list append :nr];                   // Append objects in list
// 
//   nr = [DInt alloc]; [nr init :8];
//   [list append :nr];
// 
//   str = [DText alloc]; [str init :"hello"];
//   [list append :str];
// 
//   nr7 = [DInt alloc]; [nr7 init :7];
//   [list append :nr7];
// 
//   str = [ DText alloc]; [str init :"bye"];
//   [list append :str];
// 
//   printf("List has %ld elements.\n", [list length]); // Get the lenght of the list
// 
//   nr = [DInt alloc]; [nr init :3];
//   [list insert :3 :nr];                // Insert an object in the list
// 
//   str = [DText alloc]; [str init :"replace"];
//   nr = [list set :1 :str];             // Index 2 is replaced by "replace"
//   [nr free];
// 
//   str = [list get :2];                 // Get an object from the list
//   printf("Element 2 is \"%s\".\n", [str cstring]);
// 
//   printf("List contains object nr7 %ld times.\n", [list count :nr7]); // Count occurences
// 
//   printf("Index of object nr7 is %ld.\n", [list index :nr7]); // Find index of object
// 
//   if ([list remove :nr7])              // Remove an object from the list
//   {
//     printf("Object nr7 is removed from the list.\n");
//     [nr7 free];
//   }
//   else
//     printf("Object nr7 could not be found in the list.\n");
// 
//   str = [list join :','];              // Join all objects text to one text object
//   printf("Join of all objects text in the list:%s.\n", [str cstring]);
//   [str free];
// 
//                                        // Iterate the list
//   iter = [DListIterator new];
// 
//   [iter list :list];                   // Set the list in the iterator
// 
//   obj = [iter last];                   // Iterate the list backwards
//   while (obj != nil)
//   {
//     if ([obj isKindOf :[DText class]]) // Find out the type of the object and ..
//     {
//       str = obj;
//       printf("Element: %s.\n", [str cstring]); // .. print the contents
//     }
//     else
//       if ([obj isKindOf :[DInt class]])
//       {
//         nr = obj;
//         printf("Element: %d\n", [nr get]);
//       }
//       else 
//         printf("Element: unknown.\n");
//     obj = [iter prev];
//   }
// 
//   [iter free];                         // Cleanup
//   [list free];
// 
//   return 0;
// }
// 

typedef int (*DListCompare)(id obj1, id obj2);

@interface DList : DObject <DStackable,DQueuable,DTextable>
{
@private
  DListNode      *_first;   // the start of the list
  DListNode      *_last;    // the end of the list
  long            _count;   // the number of nodes in the list
}

#endif



@implementation DList


#if _PRIVATE_

static DListNode *newNode(DList *list, id obj)
{
  DListNode *node = (DListNode *) objc_malloc(sizeof(DListNode));

  node->_next   = NULL;
  node->_prev   = NULL;
  node->_object = obj;

  (list->_count)++;
  
  return node;
}

static void shallowFreeNode(DList *list, DListNode *node)
{
  node->_next   = NULL;
  node->_prev   = NULL;
  node->_object = nil;

  (list->_count)--;

  objc_free(node);
}

static void freeNode(DList *list, DListNode *node)
{
  if (node->_object != nil)
    [node->_object free];

  shallowFreeNode(list, node);
}

static DListNode *getFirstNode(DList *list)
{
  return list->_first;
}

static DListNode *getLastNode(DList *list)
{
  return list->_last;
}

static DListNode *index2node(DList *list, long index)
{
  DListNode *node;
  
  if (index >= 0)
  {
    node = list->_first;
    
    while ((node != NULL) && (index > 0))
    {
      node = node->_next;
      
      index--;
    }
  }
  else
  {
    index = -(index + 1);
    
    node = list->_last;
    
    while ((node != NULL) && (index > 0))
    {
      node = node->_prev;
      
      index--;
    }
  }
  
  return node;
}

static DListNode *insertBefore(DList *list, DListNode *node, id obj)
{
  DListNode *extra = newNode(list, obj);

  if (node == NULL)
  {
    node = list->_first;
  }
      
  if (node == NULL)
  {
    list->_first = extra;
    list->_last  = extra;
  }
  else
  {
    if (node->_prev != NULL)
      node->_prev->_next = extra;
    
    extra->_prev = node->_prev;
    node ->_prev = extra;
    extra->_next = node;
    
    if (node == list->_first)
      list->_first = extra;
  }
  
  return extra;
}

static DListNode *insertAfter(DList *list, DListNode *node, id obj)
{
  DListNode *extra = newNode(list, obj);

  if (node == NULL)
  {
    node = list->_last;
  }
      
  if (node == NULL)
  {
    list->_first = extra;
    list->_last  = extra;
  }
  else
  {
    if (node->_next != NULL)
      node->_next->_prev = extra;
    
    extra->_next = node->_next;
    node ->_next = extra;
    extra->_prev = node;
    
    if (node == list->_last)
      list->_last = extra;
  }
  
  return extra;
}

static void removeNode(DList *list, DListNode *node)
{
  if (node->_prev == NULL)
  {
    list->_first = node->_next;
  }
  else
  {
    node->_prev->_next = node->_next;
  }
  
  if (node->_next == NULL)
  {
    list->_last = node->_prev;
  }
  else
  {
    node->_next->_prev = node->_prev;
  }

    
  shallowFreeNode(list, node);
}

#endif



//// Constructors

//
// Initialise an empty list
//
// @return the list
//

- (DList *) init
{
  [super init];

  _first = NULL;
  _last  = NULL;
  _count = 0;
  
  return self;
}


//// Copy related methods

//
// Do a shallow copy of the object
// 
// @return the copy
// 
- shallowCopy
{
  DList *copy = [super shallowCopy];
  
  DListNode *node = _first;
  
  copy->_first = NULL;
  copy->_last  = NULL;
  copy->_count = 0;
  
  while (node != NULL)
  {
    insertAfter(copy, copy->_last, node->_object);
                
    node = node->_next;
  }
  
  return copy;
}

//
// Deepen a copied object
//
// @return the object
//
- deepen
{
  DListNode *node;
  
  [super deepen];

  node = _first;
  
  while (node != NULL)
  {
    if (node->_object != nil)
    {
      node->_object = [node->_object copy];
    }
                
    node = node->_next;
  }
  
  return self;
}


//// Deconstructor

//
// Free the list (the stored objects are *NOT* freed)
//
// @return the instance
//

- shallowFree
{
  DListNode *node;
  
  while (_first != NULL)
  {
    node = _first->_next;
    
    shallowFreeNode(self, _first);

    _first = node;
  }
  
  [super free];
  
  return self;
}

//
// (Deep) free the list (the stored objects are *FREED*)
//
// @return the instance
//

- free
{
  DListNode *node;
  
  while (_first != NULL)
  {
    node = _first->_next;
    
    freeNode(self, _first);

    _first = node;
  }
  
  [super free];
  
  return self;
}




//// Member methods

//
// Check if the list is empty
//
// @return is the list empty ?
//

- (BOOL) isEmpty
{
  return (_count == 0);
}

// Return the length of the list
//
// @return the number of nodes in the list
//

- (long) length
{
  return _count;
}

  
//// List manipulation methods

//
// Prepend an object to the list
//
// @param object   the object that must be prepended
//
// @return the list
//

- (DList *) prepend :(id) object
{
  insertBefore(self, _first, object);
  
  return self;
}

//
// Append an object to the list
//
// @param object   the object that must be appended
//
// @return the instance
//

- (DList *) append :(id) object
{
  insertAfter(self, _last, object);
    
  return self;
}

//
// Insert an object in the list on the given index
//
// @param index    the index in the list (-n..+n)
// @param object   the object to be inserted
//
// @return the list
//

- (DList *) insert :(long) index :(id) object
{
  if (index < 0)
  {
    index = _count - index;
 
    if (index < 0)
    {
      index = 0;
    }   
  }
  
  if (index >= _count)
  {
    [self append :object];
  }
  else if (index == 0)
  {
    [self prepend :object];
  }
  else
  {
    DListNode *node = _first;
    
    while ((index > 0) && (node != NULL))
    {
      node = node->_next;
      
      index--;
    }
    
    if (node != NULL)
    {
      insertBefore(self, node, object);
    }
    else
    {
      WARNING(DW_UNEXPECTED_ERROR, "list is corrupt");
    }
  }

  return self;
}

//
// Set the object in a list node
//
// @param index    the index in the list
// @param object   the object to be set
// 
// @return the previous stored object
//

- (id) set :(long) index :(id) object
{
  id         prev = nil;
  
  DListNode *node = index2node(self, index);
  
  if (node != NULL)
  {
    prev = node->_object;
    
    node->_object = object;
  }
  else
    WARNING(DW_ARG_OUT_RANGE, "index");
  
  return prev;
}

//
// Get the object in a list node
//
// @param index    the index in the list
//
// @return the stored object
//

- (id) get :(long) index
{
  DListNode *node = index2node(self, index);

  return (node != NULL) ? node->_object : nil;
}

//
// Get a range of objects from the list
//
// @param from     the start index from the range
// @param to       the end index from the range
//
// @return a (new) list with (references) to the objects
//

- (DList *) get :(long) from :(long) to
{
  DList *list = [[DList alloc] init];
  
  DListNode *srce = index2node(self, from);
  DListNode *dest = index2node(self, to  );
 
  if (srce == NULL)
  {
    WARNING(DW_ARG_OUT_RANGE, "from");
  }
  else if (dest == NULL)
  {
    WARNING(DW_ARG_OUT_RANGE, "to");
  }
  else
  {
    DListNode *node = srce;

    BOOL done = NO;
    
    while (!done)
    {
      [list append :(node->_object)];
      
      if (node == dest) 
        done = YES;

      node = node->_next;

      if (node == NULL) 
        node = _first;
      if (node == srce) 
        done = YES;
    }
  }

  return list;
}

//
// Delete a list node
//
// @param index    the index in the list
//
// @return the stored object
//

- (id) delete :(long) index
{
  id         prev = nil;
  
  DListNode *node = index2node(self, index);
  
  if (node != NULL)
  {
    prev = node->_object;

    removeNode(self, node);
  }
  else
  {
    WARNING(DW_ARG_OUT_RANGE, "index");
  }
  
  return prev;
}

//
// Delete a range of list nodes
//
// @param from    the first index in the list
// @param to      the last index in the list (to >= from)
//
// @return a (new) list with the deleted list nodes
//

- (DList *) delete :(long) from :(long) to
{
  DList *list = [[DList alloc] init];
  
  DListNode *srce = index2node(self, from);
  DListNode *dest = index2node(self, to  );
 
  if (srce == NULL)
  {
    WARNING(DW_ARG_OUT_RANGE, "from");
  }
  else if (dest == NULL)
  {
    WARNING(DW_ARG_OUT_RANGE, "to");
  }
  else
  {
    DListNode *node = srce;
    DListNode *next = NULL;
    
    BOOL done = NO;
    
    while (!done)
    {
      [list append :(node->_object)];
      
      if (node == dest) 
        done = YES;

      next = node->_next;

      removeNode(self, node);

      node = next;

      if (node == NULL) 
        node = _first;
      if (node == srce) 
        done = YES;
    }
  }

  return list;
}

//
// Count the number of occurrences of an object in the list
//
// @param object   the object that must be counted (incl. nil)
//
// @return the number of occurrences
//

- (long) count :(id) object
{
  long count = 0;

  DListNode *node = _first;
  while (node != NULL)
  {
    if (node->_object == object)
    {
      count++;
    }
    node = node->_next;
  }
  
  return count;
}

//
// Find the smallest index where an object is located
//
// @param object   the object that must be located
//
// @return the index in the list (or -1 if not found)
//

- (long) index :(id) object
{
  long index = 0;
  
  DListNode *node = _first;
  while ((node != NULL) && (node->_object != object))
  {
    node = node->_next;
    
    index++;
  }
  
  if (node == NULL)
  {
    index = -1;
  }
  
  return index;
}

//
// Find the largest index where an object is located
//
// @param object   the object that must be located in the list
//
// @return the index in the list (or -1 if not found)
//

- (long) rindex :(id) object
{
  long index = _count - 1;
  
  DListNode *node = _last;
  while ((node != NULL) && (node->_object != object))
  {
    node = node->_prev;
    
    index--;
  }
  
  return index;
}

//
// Check if the object is in the list
//
// @param object   the object that must be located in the list
//
// @return is the object in the list ?
//

- (BOOL) has :(id) object
{
  DListNode *node = _first;
  while ((node != NULL) && (node->_object != object))
  {
    node = node->_next;
  }
  
  return (node != NULL);
}

//
// Replace in the list max times every occurence of the original object
// by the replacement (orig in NOT freed)
//
// @param orig     the original object
// @param repl     the replacement object
// @param max      the maximum number of replacements (-1 = all)
//
// @return the number of actual replacements
//
- (long) replace :(id) orig :(id) repl :(long) max
{
  long count = 0L;
  
  DListNode *node = _first;
  
  while ((node != NULL) && ((max > 0) || (max == -1L)))
  {
    if (node->_object == orig)
    {
      node->_object = repl;
      
      count++;
      
      if (max > 0)
      {
        max--;
      }
    }
    
    node = node->_next;
  }
  
  return count;
}


//
// Remove the first occurrence of an object in the list
//
// @param object   the object that must be removed from the list
//
// @return success
//

- (BOOL) remove :(id) object
{
  // Find the node with the object
  DListNode *node = _first;
  while ((node != NULL) && (node->_object != object))
  {
    node = node->_next;
  }
  
  // Remove it from the list
  if (node != NULL)
  {
    if (node->_prev == NULL)
    {
      _first = node->_next;
    }
    else
    {
      node->_prev->_next = node->_next;
    }
    
    if (node->_next == NULL)
    {
      _last = node->_prev;
    }
    else
    {
      node->_next->_prev = node->_prev;
    }
    
    shallowFreeNode(self, node);
  }
  
  return (node != NULL);
}

//
// Reverse the list
//
// @return the list object
//

- (DList *) reverse
{
  DListNode *node = _first;
  DListNode *next =  node;
  
  // reverse the list
  while (node != NULL)
  {
    next = node->_next;
    
    node->_next = node->_prev;
    node->_prev = next;
    
    node = next;
  }
  
  // reverse the first and last
   node  = _first;
  _first = _last;
  _last  = node;
  
  return self;
}

//
// Perform a method for every object in the list
//
// @param sel      the selector of the method
//
// @return the object
//

- (DList *) each :(SEL) sel
{
  DListNode *node = _first;
  while (node != NULL)
  {
    if (node->_object != nil)
    {
      [node->_object perform :sel];
    }

    node = node->_next;
  }

  return self;
}

//
// Sort the list, using mergesort
//
// @param compare   the compare function, returns the compare result: smaller(<0), equal(0) or greater(>0)
//
// @return the object
//
- (DList *) sort :(DListCompare) compare
{
  int size = 1;
  DListNode *first = _first;
  DListNode *last  = NULL;
  
  BOOL done = NO;
  while (!done)
  {
    DListNode *node1 = first;
    DListNode *node2 = NULL;
    int        size1 = 0;
    int        size2 = 0;

    
    first = NULL;
    last  = NULL;

    int steps = 0;
    while (node1 != NULL)
    {
      steps++;
    
      node2 = node1;
      size1 = 0;
      while ((size1 < size) && (node2 != NULL))
      {
        node2 = node2->_next;
        size1++;
      }
      size2 = size;
      
      DListNode *node;
      while ((size1 > 0) || ((size2 > 0) && (node2 != NULL)))
      {
        if (size1 == 0)
        {
          node  = node2;
          node2 = node2->_next;
          size2--;
        }
        else if ((size2 == 0) || (node2 == NULL))
        {
          node  = node1;
          node1 = node1->_next;
          size1--;
        }
        else if (compare(node1->_object, node2->_object) <= 0)
        {
          node  = node1;
          node1 = node1->_next;
          size1--;
        }
        else
        {
          node  = node2;
          node2 = node2->_next;
          size2--;
        }
        
        if (last != NULL)
        {
          last->_next = node;
        }
        else
        {
          first = node;
        }
        node->_prev = last;
        
        last = node;
      }
      node1 = node2;
    }
    last->_next = NULL;
    done  = (steps <= 1);
    size *= 2;
  }

  _first = first;
  _last  = last;
  
  return self;
}


//// Stackable protocol methods

//
// Push a new node with the object at the end of the list
//
// @param obj      the object to be pushed
//
// @return success
//
- (BOOL) push :(id) obj
{
  [self append :obj];
  
  return YES;
}

//
// Pop the last node from the list and returns the object
//
// @return the object from the list (or nil)
//

- (id) pop
{
  id object = nil;
  
  if (_last != NULL)
  {
    DListNode *node = _last;
    
    object = node->_object;

    if (_first == _last)
    {
      _first = NULL;
      _last  = NULL;
    }
    else
    {
      _last = node->_prev;
      
      _last->_next = NULL;
    }
    
    shallowFreeNode(self, node);
  }
  
  return object;
}

//
// Return the object in the last node of the list
//
// @return the object (or nil if empty)
//

- (id) tos
{
  return ((_last != NULL) ? _last->_object : nil);
}


//// Queuable protocol methods

//
// Enqueue the object at the end of the list
//
// @param obj      the object 
//
// @return success
//
- (BOOL) enqueue :(id) obj
{
  [self append :obj];
  
  return YES;
}

//
// Dequeue the first object from the list
//
// @return the object (or nil for buffer empty)
//
- (id) dequeue
{
  id object = nil;
  
  if (_first != NULL)
  {
    DListNode *node = _first;
    
    object = node->_object;

    if (_first == _last)
    {
      _first = NULL;
      _last  = NULL;
    }
    else
    {
      _first = node->_next;
      
      _first->_prev = NULL;
    }
    
    shallowFreeNode(self, node);
  }
  
  return object;
}
  

//// String methods

//
// Split a string in a list of strings
//
// @param string    the string to be splitted
// @param seperator the seperator character
// @param maxsplits the maximum number of splits (or -1 for all)
//
// @return a (new) list with string objects
//

+ (DList *) split :(const char *) string :(char) seperator :(int) maxsplits
{
  int count = 0;
  int srce  = 0;
  int dest  = 0;
  
  DList *list = [[DList alloc] init];
  DText *text;
  
  if (seperator != EOS)
  {
    while (string[dest] != EOS)
    {
      srce = dest;
      while ((string[dest+1] != EOS) && ((string[dest+1] != seperator) || ((count >= maxsplits) && (maxsplits != -1))))
      {
        dest++;
      }
  
      text = [DText alloc];
   
      [[text init] set :string :srce :dest];  

      [list append :text];
      count++;
    
      dest++;
      while (string[dest] == seperator)
        dest++;
    }
  }
  else
    WARNING(DW_INVALID_ARG, "seperator");

  return list;
}

//
// Join the list of strings to one string
//
// @param seperator the seperator to be used
//
// @return the new string with the joined strings
//

- (DText *) join :(char) seperator
{
  DText *string = [[DText alloc] init];
  
  DListNode *node = _first;

  while (node != NULL)
  {
    if (node->_object != nil)
    {
      DText *text = [node->_object toText];

      [string append :[text cstring]];

      if (node != _last)
        [string push :seperator];

      [text free];
    }
      
    node = node->_next;
  }

  return string;
}

//
// Convert the list to a string
//
// @return the new text string
//

- (DText *) toText
{
  return [self join :','];
}

@end



#if _INTERFACE_
  
//
// The DListIterator class implements a number of methods for iterating lists.
//
// // @example
// #include <stdio.h>
// #include "ofc/DList.h"
// #include "ofc/DInt.h"
// #include "ofc/DText.h"
// 
// int main(int argc, char *argv[])
// {
//   DList         *list = [DList new];
//   DListIterator *iter;
//   DInt          *nr;
//   DText         *str;
//   DInt          *nr7;
//   id             obj;
//                                        // Add strings and numbers to the list
//   nr = [DInt alloc]; [nr init :4];
//   [list append :nr];                   // Append objects in list
// 
//   nr = [DInt alloc]; [nr init :8];
//   [list append :nr];
// 
//   str = [DText alloc]; [str init :"hello"];
//   [list append :str];
// 
//   nr7 = [DInt alloc]; [nr7 init :7];
//   [list append :nr7];
// 
//   str = [ DText alloc]; [str init :"bye"];
//   [list append :str];
// 
//   printf("List has %ld elements.\n", [list length]); // Get the lenght of the list
// 
//   nr = [DInt alloc]; [nr init :3];
//   [list insert :3 :nr];                // Insert an object in the list
// 
//   str = [DText alloc]; [str init :"replace"];
//   nr = [list set :1 :str];             // Index 2 is replaced by "replace"
//   [nr free];
// 
//   str = [list get :2];                 // Get an object from the list
//   printf("Element 2 is \"%s\".\n", [str cstring]);
// 
//   printf("List contains object nr7 %ld times.\n", [list count :nr7]); // Count occurences
// 
//   printf("Index of object nr7 is %ld.\n", [list index :nr7]); // Find index of object
// 
//   if ([list remove :nr7])              // Remove an object from the list
//   {
//     printf("Object nr7 is removed from the list.\n");
//     [nr7 free];
//   }
//   else
//     printf("Object nr7 could not be found in the list.\n");
// 
//   str = [list join :','];              // Join all objects text to one text object
//   printf("Join of all objects text in the list:%s.\n", [str cstring]);
//   [str free];
// 
//                                        // Iterate the list
//   iter = [DListIterator new];
// 
//   [iter list :list];                   // Set the list in the iterator
// 
//   obj = [iter last];                   // Iterate the list backwards
//   while (obj != nil)
//   {
//     if ([obj isKindOf :[DText class]]) // Find out the type of the object and ..
//     {
//       str = obj;
//       printf("Element: %s.\n", [str cstring]); // .. print the contents
//     }
//     else
//       if ([obj isKindOf :[DInt class]])
//       {
//         nr = obj;
//         printf("Element: %d\n", [nr get]);
//       }
//       else 
//         printf("Element: unknown.\n");
//     obj = [iter prev];
//   }
// 
//   [iter free];                         // Cleanup
//   [list free];
// 
//   return 0;
// }
//

@interface DListIterator : DObject
{
@private
  DList          *_list;    // the list on which the iterator operates
  DListNode      *_node;    // the current node in the list
}

#endif



@implementation DListIterator


//// the constructors

//
// Initialise a list iterator without a list
//
// @return the iterator
//

- (DListIterator *) init
{
  [super init];
  
  _list = nil;
  _node = NULL;
  
  return self;
}

//
// Initialise a list iterator with a list (the iterator is moved to the first node)
//
// @param list     the list on which the iterator operates
//
// @return the iterator
//

- (DListIterator *) init :(DList *) list
{
  [self init];

  [self list :list];
  
  return self;
}

//// the iterator methods

//
// Set the list (iterator is moved to the first object)
//
// @return the iterator
//

- (DListIterator *) list :(DList *) list
{
  _list = list;
  
  if (_list != nil)
  {
    _node = getFirstNode(_list);
  }
  
  return self;
}

//
// Get the first object in the list
//
// @return the first object (or nil)
//

- (id) first
{
  if (_list != nil)
  {
    _node = getFirstNode(_list);
    
    return  (_node != NULL) ? _node->_object : nil;
  }
  else
    WARNING(DW_OBJECT_NOT_INIT, "list");
      
  return nil;
}

//
// Get the next object in the list
//
// @return the next object (or nil)
//

- (id) next
{
  if ((_node != NULL) && (_node->_next != NULL))
  {
    _node = _node->_next;

    return (_node->_object);
  }
  
  return nil;
}

//
// Get the previous object in the list
//
// @return the previous object (or nil)
//

- (id) prev
{
  if ((_node != NULL) && (_node->_prev != NULL))
  {
    _node = _node->_prev;

    return (_node->_object);
  }
  
  return nil;
}

//
// Get the last object in the list
//
// @return the last object (or nil)
//

- (id) last
{
  if (_list != nil)
  {
    _node = getLastNode(_list);

    return (_node != NULL) ? _node->_object : nil;    
  }
  else
    WARNING(DW_OBJECT_NOT_INIT, "list");
  
  return nil;
}

//
// Set the current object to another object
//
// @param object   the object to be placed in current node
//
// @return the previous stored object
//

- (id) object :(id) object
{
  id prev = nil;
  
  if (_node != NULL)
  {
    prev = _node->_object;
    
    _node->_object = object;
  }
  
  return prev;
}

//
// Get the current object
//
// @return the current object (or nil)
//

- (id) object
{
  return (_node != NULL) ? _node->_object : nil;
}

//
// Insert a new object before the current object (iterator is moved to the new object)
// 
// @param obj      the object to be added before the current object
// 
// @return the iterator
// 

- (DListIterator *) before :(id) obj
{
  if (_list == nil)
  {
    WARNING(DW_OBJECT_NOT_INIT, "list");
  }
  else
  {
    _node = insertBefore(_list, _node, obj);
  }
    
  return self;
}

//
// Insert a new object after the current object (iterator is moved to the new object)
// 
// @param obj      the object to be added after the current object
// 
// @return the iterator
// 

- (DListIterator *) after :(id) obj
{
  if (_list == nil)
  {
    WARNING(DW_OBJECT_NOT_INIT, "list");
  }
  else
  {
    _node = insertAfter(_list, _node, obj);
  }
    
  return self;
}
  
@end

/*===========================================================================*/

